# -*- coding: utf-8 -*-

'''
This file is a textobot AppleID auto login plugin implementation demo.

It's developed on iOS 12.4, run on other iOS version should modify some label text.
'''

import os
import codecs
import time
import subprocess
import json
import frida

# our target bundleID
target_bid = 'com.apple.Preferences'

# it's only for VSCode Textobot-Run command
# turn to 0 before you pack this plugin
# turn to 1 if you want to run directly from VSCode
dev_mode = 0

# turn to 1 when you finished the plugin development
# and run at least one time to flush remote server side global code 
# otherwise will conflict with the release TB plugin
dev_clear_hotcode = 0

if not dev_mode:
    # this plugin package's root directory
    pkg_root = os.path.dirname(__file__)

    # pickup this plugin's version dynamically
    with open(pkg_root + '/textobot.json', 'r') as fp:
        pkginfo = json.load(fp)
        pkg_version = pkginfo['version']

# frida device
idev = frida.get_remote_device()

# dump event information
def dump_event(dictarg):
    print('####################')
    for pt in dictarg.keys():
        text = dictarg[pt]
        print('%s len=%d, str=%s' % (pt, len(text), text))
    return {}

# input text demonstration
def input_text(pt, text):
    TB_touch_pair(pt)
    time.sleep(3)
    TB_input_text(text)
    time.sleep(3)

# run an app
def run_app(bid):
    print('start app : %s' % (bid))
    TB_launch(bid)

# run a shell command
def run_cmd(s):
    print('run cmd : %s' % (s))
    subprocess.Popen(s, shell=True).wait()

# global point & text list
points = None
texts = None
# global task status
ST_find_entry = 0
ST_input_account = 1
status = None

# stop task
def stop_task():
    # kill the Preferences process
    run_cmd('killall -9 Preferences')

# start task
def start_task():
    global status
    stop_task()
    time.sleep(1)
    # run a new Preferences process
    status = ST_find_entry
    run_app(target_bid)

def has_text(t):
    for i in range(0, len(texts)):
        if texts[i] == t:
            return points[i]
    return None

def contain_text(t):
    for i in range(0, len(texts)):
        if texts[i].find(t) >= 0:
            return points[i]
    return None

# handler for text views
def proc_event_views(pts, txts):
    global points
    global texts
    global status
    points = pts
    texts = txts

    print('current status : %d' % (status))

    # use dump_event on TB_on_event to see the texts
    if status == ST_find_entry:
        pt = has_text('UITableViewLabel.iTunes Store 与 App Store')
        if pt:
            TB_touch_pair(pt)
            status = ST_input_account
            return
        # there's no label we are finding, swipe down to up
        for i in range(0, 8):
            TB_swipe(100, 150, 100, 100)
    elif status == ST_input_account:
        pt = has_text('StoreSettingsAccountCell.登录')
        if pt:
            TB_touch_pair(pt)
            return


# handler for dialog
def proc_event_dialog(pts, txts):
    global points
    global texts
    global status
    points = pts
    texts = txts
    # use dump_event on TB_on_event to see the texts
    if has_text('UILabel.需要用 Apple ID 登录'):
        ptacc = has_text('UITextFieldLabel.Apple ID')
        ptpsw = has_text('UITextFieldLabel.密码')
        if not ptacc or not ptpsw:
            TB_dialog('Textobot', 'add code to process this situation:\n' + str(texts))
            return
        # input fake account
        input_text(ptacc, 'test@test.com')
        input_text(ptpsw, 'test')
        TB_touch_pair(has_text('UILabel.登录'))
    elif contain_text('您的 Apple ID 已被锁定') or \
        contain_text('验证失败'):
        TB_dialog('Textobot', 'The fake account of course cannot login, restart a new task in 5s...')
    elif contain_text('restart a new task in 5s') and \
        status == ST_input_account:
        time.sleep(5)
        TB_touch_pair(contain_text('OK'))
        time.sleep(2)
        start_task()

# fire javascript to target app
def fire_javascript(bid, pid):
    # we don't need process level javascript plugin code in this plugin
    pass

# handler for event
def TB_on_event(dictarg):
    # comment off when you want to see the incoming texts
    # use VSCode Textobot-Log command to see them
    #dump_event(dictarg)

    target = dictarg['target']
    event = dictarg['event']
    if event == 'texts':
        proc_event_views(dictarg.keys(), dictarg.values())
    elif event == 'dlgtexts':
        proc_event_dialog(dictarg.keys(), dictarg.values())
    return {}

# handler for main
def TB_main(dictarg):
    #dump_event(dictarg)

    event = dictarg['event']
    if event == 'install':
        print('install AppleIDLogin plugin')
    elif event == 'uninstall':
        print('uninstall AppleIDLogin plugin')
    elif event == 'start':
        print('start AppleIDLogin plugin')
        start_task()
    elif event == 'stop':
        print('stop AppleIDLogin plugin')
        stop_task()
    return {}

# it's only for VSCode Textobot-Run command, can only recv TB_on_event
if dev_mode:
    # only available in dev mode
    TB_clear_log()
    if dev_clear_hotcode:
        TB_event_callback = None
        stop_task()
        print('Cleared dev hot code...')
    else:
        TB_event_callback = TB_on_event
        start_task()
        print('The AppleIDLogin plugin(dev) is waiting for event ...')
# running in release plugin mode, can recv TB_on_event & TB_main
else:
    print('The AppleIDLogin plugin(%s) is waiting for event ...' % (pkg_version))
